<?php
/**
 * 状态模式: 允许对象在运行期间内部状态值改变后 改变行为 , 这看上去像是更改了对象
 *
 * 1. 状态上下文 , 记录/设置 当前状态
 * 2. 实际状态对象
 *
 * 上下文处理的时候,将自己的状态分发到当前实际状态对象来处理
 * 如果实际状态对象可以处理就处理 , 如果不能处理则交给下一状态来处理 (实际状态对象 修改 上下文的状态,将新的状态对象设置到上下文中),
 * 最后一个状态还没有处理 , 则抛出异常
 *
 * 优点: 每种状态只需要处理自己对应状态的业务即可 , 符合 单一职责
 *       即使需要新增状态 , 也只需要添加一个状态类来处理, 不用修改原有的代码 , 符合 开闭原则
 *
 *
 * */

class Man{
    protected $time = 10;
    protected $state = null;

    public function setState($state){
        $this->state = $state;
        return $this;
    }
    public function getTime(){
        return $this->time;
    }
    /**
     * 将所有的状态全部写在一起来处理
     * 1.如果要修改 业务 必然违背开闭原则
     * 2.如果状态过多 , 必然造成片的代码 , 代码过长
     * */
    public function nowState(){
        if ($this->time < 9) {
            echo '当前为上午,状态不是一般好! 努力写代码';
        }else if($this->time < 12) {
            echo '快要中午了,有些小饿';
        }else if($this->time < 14) {
            echo '吃完饭了,有些想睡觉';
        }else if($this->time < 17) {
            echo '状态不佳,下午疲惫';
        }
    }
    /**
     * 获取当前状态信息
     * 交给每个状态对象来处理
     *
     *
     * */
    public function getNowState(){
        $this->state->nowState($this);
    }
}

class State9{
    public function nowState(Man $ctx){
        if($ctx->getTime() < 9) {
            echo '9点前的状态真的好,写代码真爽';
        }else{
            $ctx->setState(new State12())->getNowState($ctx);
        }
    }
}

class State12{
    public function nowState(Man $ctx){
        if($ctx->getTime() < 12) {
            echo '快要中午了,有些小饿';
        }else{
            $ctx->setState(new State14())->getNowState($ctx);
        }
    }
}

class State14{
    public function nowState(Man $ctx){
        if($ctx->getTime() < 14) {
            echo '吃完饭了,有些想睡觉';
        }else{
            $ctx->setState(new State17())->getNowState($ctx);
        }
    }
}

class State17{
    public function nowState(Man $ctx){
        if($ctx->getTime() < 17) {
            echo '状态不佳,下午疲惫';
        }else{
            throw new Exception('未捕获的状态!');
        }
    }
}

(new Man())->setState(new State9())->getNowState();



/*
 *    1  0
 *    2  0
 *    3  0,1
 *    4  0,1,3
 *    5  0,1,3,4
 *    6  0,2
 *    7  0,2,6
 *    8  0,2,6,7
 * */